import React, { useEffect, useMemo, useRef, useState, forwardRef } from 'react';
import { DeleteOutlined, EyeOutlined, PlusOutlined } from '@ant-design/icons';
import { App, Modal, Progress, Upload } from 'antd';
import { ClockCircleOutlined } from '@ant-design/icons';

import { uploadImage } from '@/service/base';
import { getUuid } from '@/utils';
import styles from './index.module.scss';


// 处理图片文件，获取宽度、高度
const processImageFile = (file) => {
    return new Promise((resolve, reject) => {
        let img = new Image();
        const url = URL.createObjectURL(file);
        img.src = url;
        img.onload = () => {
            URL.revokeObjectURL(url);
            resolve({ width: img.width, height: img.height });
            img = null;
        };
        img.onerror = () => {
            URL.revokeObjectURL(url);
            reject(new Error(`无法加载图片: ${file.name}`));
        };
    });
};
// 计算比例的100倍值
const parseAspectRatio = (ratio) => {
    if (!ratio) return null;
    const parts = ratio.split(':').map(Number);
    return parseInt(parts[0] / parts[1] * 100);
};

export default forwardRef((props, ref) => {
    const { message } = App.useApp();
    const {
        className,
        enableMainImage = false,
        maxCount = undefined,
        accept,
        maxSize = 0,
        widthRange = [],
        heightRange = [],
        aspectRatio,
        buttonText = '选择文件',
        disabled = false,
        shape = 'square',
        value,
        onChange,
        onUploadingChange,
        concurrency = 3,
    } = props;


    const [fileList, setFileList] = useState([]);
    const [mainImage, setMainImage] = useState('');
    const [previewOpen, setPreviewOpen] = useState(false);
    const [previewUrl, setPreviewUrl] = useState('');
    const queueRef = useRef([]);
    const uploaderRef = useRef(null);
    const ratioValue = useMemo(() => parseAspectRatio(aspectRatio), [aspectRatio]);
    const fileListRef = useRef([]);
    const mainImageRef = useRef('');
    const isUploadingRef = useRef(false);
    const controllersRef = useRef(new Map());
    const progressTsRef = useRef(new Map());
    const toThumbUrl = (url) => {
        if (!url) return '';
        const p = 'x-oss-process=image/resize,w_256/quality,q_40';
        return url.includes('?') ? `${url}&${p}` : `${url}?${p}`;
    };

    // 文件预检
    const validateFile = async (file) => {
        if ((!widthRange || !widthRange.length) && (!heightRange || !heightRange.length) && !maxSize && !ratioValue) return '';

        try {
            const size = file.size;
            if (maxSize && size > maxSize) return `图片应小于：${maxSize} Bytes`;
            if (!file.type.startsWith('image/')) return ''; // 如果不是图片就返回，下面的判断都是图片的判断

            const { width, height } = await processImageFile(file) || {};
            if (widthRange && widthRange.length && (width < widthRange[0] || width > widthRange[1])) return `图片宽度：[${widthRange.toString()}]`;
            if (heightRange && heightRange.length && (height < heightRange[0] || height > heightRange[1])) return `图片高度：[${heightRange.toString()}]`;
            if (ratioValue) {
                const r = width / height;
                if (parseInt(r * 100) !== ratioValue) return `图片宽高比应为：${aspectRatio}`;
            }
            return '';
        } catch(e) {}

        return '';
    };

    // 开始上传队列任务
    const tryStartUploads = async () => {
        if (isUploadingRef.current) return;
        onUploadingChange(true);
        isUploadingRef.current = true;
        try{
            const worker = async () => {
                while (true) {
                    const next = queueRef.current.shift();
                    if (!next) break;
                    await startUpload(next);
                }
            };
            const workerCount = concurrency || 5;
            const workers = Array.from({ length: workerCount }, () => worker());
            await Promise.all(workers);

            // startUpload 中的state的更新是异步的，需要等待
            let t = setTimeout(() => {
                clearTimeout(t);

                const urls = (fileListRef.current || []).filter(f => f.status === 'done' && f.url).map(f => f.url);
                if (enableMainImage && !mainImageRef.current && urls.length) {
                    const mi = urls[0];
                    mainImageRef.current = mi;
                    setMainImage(mi);
                }
                const payload = enableMainImage ? { images: urls, mainImage: mainImageRef.current } : { images: urls };
                onChange(payload);
            }, 100);
        }finally{
            isUploadingRef.current = false;
            onUploadingChange(false);
        }
    };

    // 执行上传
    const startUpload = async (fileObj) => {
        const { uid, file } = fileObj || {};
        setFileList(o => {
            const next = o.map(f => f.uid === uid ? { ...f, status: 'uploading', percent: 0 } : f);
            fileListRef.current = next;
            return next;
        });

        try {
            const formData = new FormData();
            formData.append('file', file);
            const controller = new AbortController();
            controllersRef.current.set(uid, controller);
            const [res, err] = await uploadImage(formData, (e) => {
                const p = e && e.total ? (e.loaded / e.total) * 100 : 0;
                const now = Date.now();
                const last = progressTsRef.current.get(uid) || 0;
                if (p === 100 || now - last >= 100) {
                    progressTsRef.current.set(uid, now);
                    setFileList(o => {
                        const next = o.map(f => f.uid === uid ? { ...f, percent: p } : f);
                        fileListRef.current = next;
                        return next;
                    });
                }
            }, controller.signal);

            if(err) {
                setFileList(o => {
                    const next = o.map(f => f.uid === uid ? { ...f, percent: 0, status: 'error', errMsg: err?.message || '上传失败' } : f);
                    fileListRef.current = next;
                    return next;
                });
            }else{
                let selectedMainImage = null;
                setFileList(o => {
                    const next = o.map(f => f.uid === uid ? { ...f, percent: 100, status: 'done', url: res.data } : f);
                    fileListRef.current = next;
                    if (enableMainImage && !mainImageRef.current) {
                        const first = next.find(i => i.status === 'done' && i.url);
                        selectedMainImage = first ? first.url : null;
                    }
                    return next;
                });
                if (enableMainImage && !mainImageRef.current && selectedMainImage) {
                    mainImageRef.current = selectedMainImage;
                    setMainImage(selectedMainImage);
                }
            }
        } catch (err) {
            setFileList(o => {
                const next = o.map(f => f.uid === uid ? { ...f, percent: 0, status: 'error', errMsg: err?.message || '上传失败' } : f);
                fileListRef.current = next;
                return next;
            });
        } finally {
            controllersRef.current.delete(uid);
            try { progressTsRef.current.delete(uid); } catch(e) {}
        }
    };

    // 确定上传文件（允许重复上传）
    const handleChange = async (e) => {
        e?.preventDefault?.();
        e?.stopPropagation?.();
        const existingCount = (fileListRef.current || []).length;
        const remain = maxCount ? Math.max(maxCount - existingCount, 0) : Infinity;
        let incoming = Array.from(e.target.files || []);
        if (remain <= 0) {
            if (uploaderRef.current) uploaderRef.current.value = '';
            return;
        }
        if (incoming.length > remain) {
            incoming = incoming.slice(incoming.length - remain);
        }
        let toUploadFiles = [];

        if(!incoming.length) return;
        for (const fi of incoming) {
            const errMsg = await validateFile(fi);
            const uid = getUuid(); // uid唯一，如果不允许重复上传那么这里就需要额外的判断
            if (errMsg) {
                toUploadFiles.push({uid, file: fi, status: 'error', errMsg});
            }else{
                toUploadFiles.push({uid, file: fi, status: 'ready', percent: 0});
                queueRef.current.push({uid, file: fi});
            }
        }

        // 追加到现有列表，保留之前已完成的文件
        setFileList(prev => {
            const nextList = (prev || []).concat(toUploadFiles);
            fileListRef.current = nextList;
            return nextList;
        });

        // 去执行上传请求
        tryStartUploads();
        if (uploaderRef.current) uploaderRef.current.value = '';
    };

    // 设置主图
    const setPrimary = (imgUrl, e) => {
        e?.stopPropagation();

        const urls = (fileList || []).map(i => i.url).filter(Boolean);
        onChange({ images: urls, mainImage: imgUrl });
    };
    // 图片预览
    const handlePreview = (file, e) => {
        e?.stopPropagation();

        const url = file?.url || '';
        if (!url) return;
        setPreviewUrl(url);
        setPreviewOpen(true);
    };
    const handleDelete = (file, e) => {
        e?.stopPropagation();

        setFileList(prev => {
            const nextList = (prev || []).filter(f => f.uid !== file.uid);
            fileListRef.current = nextList;
            return nextList;
        });
        queueRef.current = (queueRef.current || []).filter(q => q.uid !== file.uid);
        const c = controllersRef.current.get(file.uid);
        if (c) {
            try { c.abort(); } catch(e) {}
            controllersRef.current.delete(file.uid);
        }
        try { progressTsRef.current.delete(file.uid); } catch(e) {}
        
        let t = setTimeout(() => {
            clearTimeout(t);

            const urls = (fileListRef.current || []).filter(i => i.status === 'done' && i.url).map(i => i.url);
            if (enableMainImage && mainImageRef.current && mainImageRef.current === (file.url || '')) {
                const first = (fileListRef.current || []).find(i => i.status === 'done' && i.url);
                const mi = first ? first.url : '';
                mainImageRef.current = mi;
                setMainImage(mi);
            }
            const payload = enableMainImage ? { images: urls, mainImage: mainImageRef.current } : { images: urls };
            onChange(payload);
        }, 100);
    };
    const getActionButton = (file) => {
        const showView = ['done'].includes(file.status);
        const showDelete = !disabled && ['done', 'error'].includes(file.status);

        return (
            <div className={styles['actions']}>
                <div className={styles['btn']}>
                    { showView && <div className={styles['button']} onClick={handlePreview.bind(null, file)}><EyeOutlined /></div> }
                    { showDelete && <div className={styles['button']} onClick={handleDelete.bind(null, file)}><DeleteOutlined /></div> }
                </div>
            </div>
        );
    };
    const itemRender = (file, index) => {
        const imgUrl = file.url || '';

        return (
            <div className={styles['upload-item']}>
                {'done' === file.status && (
                    <div className={styles[file.status]}>
                        { imgUrl ? <img src={toThumbUrl(imgUrl)} alt="" loading='lazy' decoding='async' /> : null }
                        { getActionButton(file) }
                        { enableMainImage && <div className={`${styles['set']} ${mainImage && mainImage === imgUrl ? styles['primary'] : ''}`} onClick={setPrimary.bind(null, imgUrl)}>{mainImage && mainImage === imgUrl ? '主图' : '设为主图'}</div> }
                    </div>
                )}
                {'uploading' === file.status && (
                    <div className={styles[file.status]}>
                        <img className={styles['holder-image']} src="/images/logo.png" alt="" />
                        <div className={styles['percent']}><Progress size="small" percent={parseInt(file.percent || 0)} status="active" percentPosition={{ align: 'center', type: 'outer' }} /></div>
                    </div>
                )}
                {'error' === file.status && (
                    <div className={styles[file.status]}>
                        <p>{file.errMsg || '上传失败'}</p>
                        { getActionButton(file) }
                    </div>
                )}
                {'ready' === file.status && (
                    <div className={styles[file.status]}>
                        <div className={styles['icon']}><ClockCircleOutlined style={{fontSize: 16}} /></div>
                        <p>等待上传</p>
                        <p>{file?.name}</p>
                    </div>
                )}
            </div>
        );
    };

    useEffect(() => {
        if (isUploadingRef.current) return;

        let urls = [];
        let mainImage = '';

        if (Array.isArray(value)) {
            urls = value;
        } else if (value && typeof value === 'object') {
            urls = value.images || [];
            mainImage = value.mainImage || '';
        }

        const imageList = (urls || []).filter(Boolean).map(item => ({ uid: item, name: item, status: 'done', url: item }));
        fileListRef.current = imageList;
        mainImageRef.current = mainImage;
        setFileList(imageList);
        setMainImage(mainImage);
    }, [value]);
    useEffect(() => { fileListRef.current = fileList; }, [fileList]);
    useEffect(() => { mainImageRef.current = mainImage; }, [mainImage]);
    useEffect(() => {
        return () => {
            isUploadingRef.current = false;
            queueRef.current = [];
            try { onUploadingChange(false); } catch(e) {}
            controllersRef.current.forEach(c => { try { c.abort(); } catch(e) {} });
            controllersRef.current.clear();
            try { progressTsRef.current.clear(); } catch(e) {}
            if (uploaderRef.current) uploaderRef.current.value = '';
        };
    }, []);

    return (
        <>
            <div className={`${styles['upload-container']} ${className}`}>
                <div className={styles['upload-list']}>
                    {
                        fileList.map((item, index) => {
                            return (
                                <div
                                    key={item.uid}
                                    className={`${styles['upload-item-box']} ${'circle' === shape ? styles['circle'] : ''}`}
                                >
                                    { itemRender(item, index) }
                                </div>
                            );
                        })
                    }
                    {
                        (!maxCount || fileList.length < maxCount) && (
                            <div className={`${styles['upload-item-box']} ${styles['upload-button']} ${'circle' === shape ? styles['circle'] : ''}`} onClick={() => uploaderRef.current.click()}>
                                <div className={styles['rt-upload']}>
                                    <PlusOutlined />
                                    <div style={{ marginTop: 8 }}>{buttonText}</div>
                                </div>
                            </div>
                        )
                    }
                </div>
            </div>

            {/* 上传文件的input */}
            <input style={{display:'none'}} type="file" ref={uploaderRef} onChange={handleChange} accept={accept} multiple={1 !== maxCount} form="__rt_no_form__" />
            {/* 图片预览组件 */}
            <Modal open={previewOpen} onCancel={() => setPreviewOpen(false)} footer={null} width={720} centered>
                <div style={{textAlign:'center'}}>
                    { previewUrl ? <img src={previewUrl} style={{maxWidth:'100%', maxHeight:'70vh'}} /> : null }
                </div>
            </Modal>
        </>
    );
});
